#ifndef FND_GAME_2D_THINKER_HPP
#define FND_GAME_2D_THINKER_HPP
#include <boost/function.hpp>
#include <boost/signals2/signal.hpp>
#include <sigc++/sigc++.h>
#include <boost/noncopyable.hpp>
#include "message.hpp"
#include "message_handler.hpp"
#include <iostream>
namespace FndGame2D {
 
  
  typedef sigc::signal<void, float> thinker_updater_signal2_type ;
  
  typedef std::map<std::string, boost::any> thinker_property_map ;


  class thinker 
    : boost::noncopyable {
  public:
    typedef thinker class_type ;
    static const  std::string ACTIVE ;
    static const std::string THINKER_INIT ;
    thinker_updater_signal2_type updater2 ;
    void update(float time_interval) {updater2(time_interval);}
    bool is_active() const {return m_is_active ;}
    bool handle_message(const normal_thinker_message_type& msg) { return do_handle_message(msg);}
  private:
    // if you what change the handles. change the virtual function
    virtual bool do_handle_message(const normal_thinker_message_type& msg) 
    {return message_handler.handle_message(msg.msg, msg);}
    bool set_thinker_active_message(const normal_thinker_message_type& msg) ;

  private:
    std::string m_name ;
    bool m_is_active ;
    thinker_property_map m_property_map ;
  public:
    // message handlers
    message_handle<std::string, normal_thinker_message_type> message_handler ;
    // name getter
    const std::string& name() const {return m_name ;}
  private:
    static int g_thinker_num ;
    static  const std::string& make_a_valid_name(const std::string& name) ;
  public:
    static  int get_total_created_thinker() ;
  public:			// init and uninit
    explicit thinker(const std::string& name = std::string()) ;
  public:
    virtual ~thinker() ;
  public:
    bool add_property(const std::string& key,
		      const std::string& value = std::string()) {
      if(has_property(key)) return false ;
      m_property_map[key] = std::string(value) ;
      return true ;
    }
    bool add_property(const std::string& key,
		      const char* value) {
      if(has_property(key)) return false ;
      m_property_map[key] = std::string(value) ;
      return true ;
    }
    bool reset_property(const std::string& key,
			const char* value) {
      if(!has_property(key)) return false ;
      m_property_map[key] = std::string(value) ;
      return true; 
    }
    bool reset_property(const std::string& key,
			const std::string& value) {
      return reset_property(key, value.c_str()) ;
    }
    std::string get_property(const std::string& key, 
			     const std::string& value = std::string()) const {
      if(!has_property(key)) return value ;
      try {
	return boost::any_cast<std::string>(m_property_map.find(key)->second) ;
      } catch(const boost::bad_any_cast&) {
	return value ;
      }
    }
    template<typename T>
    bool add_property(const std::string& key, T value) {
      if(has_property(key)) return false ;
      m_property_map[key] = value ;
      return true ;
    }
    template<typename T>
    T get_property(const std::string& key, T default_v = T())const {
      if(!has_property(key)) return default_v ;
      try {
	return boost::any_cast<T>(m_property_map.find(key)->second) ;
      } catch(const boost::bad_any_cast& e) {
	std::cout << "erorr " << key << " " << e.what() << std::endl ;
	return default_v ;
      }
    }
    template<typename T>
    bool reset_property(const std::string& key, T value) {
      if(has_property(key)) return false ;
      m_property_map[key] = value ;
      return true ;
    }
    bool has_property(const std::string& key)const {
      return m_property_map.find(key) != m_property_map.end() ;
    }
    class_type* baser() {return static_cast<class_type*>(this) ;}
  protected:
    // this is should move to the thinker 
    // do this job tonight!
    typedef std::map<unsigned long, sigc::connection> thinker_connection_map ;
    static thinker_connection_map thinker_connections ;
    static bool remove_connection(unsigned long id) ;
    static bool add_connection(unsigned long id, sigc::connection& c) ;
  private:
    static unsigned long current_connection_id ;
  protected:
    static unsigned long create_connection_id() ;

  } ;
}
#endif	// FND_GAME_2D_THINKER_HPP
